home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / misc / scrabble.pro < prev    next >
Text File  |  1997-07-08  |  9KB  |  343 lines

  1. ; $Id: scrabble.pro,v 1.3 1997/01/15 04:21:02 ali Exp $
  2. ;
  3. ; Copyright (c) 1988-1997, Research Systems, Inc.  All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5.  
  6.     
  7. function anagram, word    ;Return the anagram of a word.
  8.     on_error,2                      ;Return to caller if an error occurs
  9.     if strlen(word) gt 1 then begin
  10.         w = byte(word)
  11.         return, string(w[sort(w)])
  12.     endif else return, word
  13. end
  14.  
  15.  
  16. function remove_dup,a    ;Remove elements in a with duplicate anagrams.
  17. ;
  18. on_error,2              ;Return to caller if an error occurs
  19. b = a
  20. n = n_elements(a)
  21. if n le 2 then return,b
  22. for i=0,n-1 do a[i] = anagram(a[i]) ;Make into anagrams
  23. a = a[sort(a)]        ;Sort it
  24. j = 0
  25. i = 1
  26. while i lt n do begin    ;Remove identical entrys
  27.     if a[i] ne a[j] then begin
  28.         j = j+1
  29.         a[j] = a[i]
  30.         endif
  31.     i = i+1
  32.     endwhile
  33. return, a[0:j]        ;Return result
  34. end
  35.  
  36. function remainder, word, part    ;Return chars in word not contained in part.
  37. ;
  38. ; List of common suffixes:
  39. ;
  40. on_error,2                              ;Return to caller if an error occurs
  41. suf = ['ing','er','s','tion','ed','ist','ize','al']
  42. if strlen(part) ge strlen(word) then return,"" ;Nothing left
  43. w = byte(word)
  44. p = byte(part)
  45. for i=0,strlen(part)-1 do begin
  46.     j = where(w eq p[i])
  47.     w[j[0]] = 0
  48.     endfor
  49. a = anagram(string(w[where(w ne 0)]))    ;Remainder...
  50.  
  51. ; Indicate possible suffix with upper case:
  52. for i=0,n_elements(suf)-1 do begin
  53.     if strpos(a,anagram(suf[i])) ge 0 then a = strupcase(a)
  54.     end
  55. return,a
  56. end
  57.     
  58.  
  59.  
  60.  
  61. function part_word, word, nchars    ;Forward definition for recursive fcn
  62. on_error,2                              ;Return to caller if an error occurs
  63. return,0
  64. end
  65.  
  66. function part_word, word, nchars    ;Return all the sets of nchars letters
  67.   ;in word, without regard to order.  nchars must be less than strlen(word).
  68.   ;Even though it's not supposed to happen, this procedure is recursive.
  69.   ;
  70. on_error,2                      ;Return to caller if an error occurs
  71. n = strlen(word)
  72. if n lt nchars then return,result    ;Return undefined if nchars > length
  73. if n eq nchars then begin    ; If getting all letters, return original
  74.     rslt = strarr(1)
  75.     rslt[0] = word
  76.   endif else begin
  77. ;
  78.     k = 1
  79.     for i=nchars, n-1 do k = k * (i+1) ;Total # of elements required
  80.     rslt = strarr(k)    ;Make result
  81.     k = 0
  82.     n2 = n-2
  83.     b = byte(word)
  84.     t = b[1:*]        ;Remove 1st char
  85.     s = indgen(n)
  86.     i = 0            ;Remove each character for n combinations
  87. loop:        ;Avoid for loops for recursion
  88.     w = string(t)        ;Back to string
  89.     if nchars ne (n-1) then q = part_word(w, nchars) $ ;Get new combs
  90.     else q = w
  91.     rslt[k] = q            ;store in result
  92.     k = k + n_elements(q)        ;Bump ptr
  93.     t[i < n2] = b[i]    ;Substitute next. last doesnt matter
  94.     i = i + 1
  95.     if i lt n then goto, loop
  96.   endelse
  97. return, rslt
  98. end
  99.  
  100.  
  101.  
  102. function find_word, word, lun  ;Find, using binary search technique,  the
  103. ; words with the same anagram as word.
  104. ;
  105. ;print,format="($, 1x,a)",word
  106.  
  107. common scrabble, ptr
  108.  
  109. on_error,2              ;Return to caller if an error occurs
  110.  
  111. w = anagram(word)    ;Get the word
  112. ;print,"Looking up ",word,", anagram = ",w
  113.  
  114. low = 0            ;low limit
  115. high = n_elements(ptr)-1        ;High limit
  116. a = ""
  117. mid = (low + high) /2    ;midpoint
  118.  
  119. while (low le high) do begin    ;Loop
  120.     mid = (low + high)/2    ;midpoint index
  121.     point_lun, lun, ptr[mid] ;^ to proper line
  122.     readf,lun, a        ;Read line
  123.     w1 = strmid(a, 0, strpos(a," ")) ;Extract anagram
  124.     if w1 eq w then begin    ;Found it, separate words.
  125.         a = strmid(a,strpos(a," ")+1,1000)
  126.         return,a    ;Got it
  127.       endif            ;match
  128.     if w1 lt w then low = mid + 1 $    ;move fwds
  129.     else high = mid -1
  130. endwhile
  131. ;print,"Couldn't find anagram for: ", word
  132. return,""        ;Return null string for nothing
  133. end
  134.  
  135.  
  136. function head,str    ;Remove the head of str, return it.  blanks are
  137.             ;delimiters.
  138. on_error,2              ;Return to caller if an error occurs
  139. i = strpos(str," ")
  140. if i ge 0 then begin
  141.     r=strmid(str,0,i)
  142.     str = strmid(str,i+1,1000)
  143.   endif else begin
  144.     r = str
  145.     str = ""
  146.   endelse
  147. return,r
  148. end
  149.  
  150.  
  151. pro make_anagram, lun    ;Make the anagram file
  152.  
  153. on_error,2              ;Return to caller if an error occurs
  154. print, "Creating file anagrams.dat.  This will take about 5 minutes."
  155. print,systime()
  156.  
  157. spawn, "wc /usr/dict/words", out
  158. i = strpos(out[0],"\")    ;Remove leading line, might not work with all shells
  159. out = strtrim(strmid(out[0],i+1,100),1) ;Also, remove leading blanks
  160. wc = long(strmid(out,0,strpos(out," "))) ;Should be # of words
  161. print, "Reading ",wc," words"
  162.  
  163.  
  164. a = strarr(wc)        ;Make string array for all words
  165. b = strarr(wc+1)    ;String array for anagrams
  166. get_lun, lun1
  167. openr,lun1,'/usr/dict/words'
  168. readf,lun1,a        ;Read words
  169. close,lun1
  170. ;
  171. print,"Making anagrams."
  172. for i=0,wc-1 do begin
  173.     c = strlowcase(a[i])    ;Cvt to lower
  174.     a[i] = c
  175.     if strlen(c) gt 1 then begin
  176.         c = byte(c)    ;Get into bytes, and sort by character
  177.         b[i] = string(c[sort(c)]) ;back to string
  178.       endif else b[i] = c
  179.     endfor
  180. ;
  181. ;    Now sort the anagram array b:
  182. ;
  183. print,"Sorting anagrams."
  184. c = sort(b)    ;into lexical order
  185. ;
  186. print,"Writing output."
  187. openw,lun,'anagrams.dat'
  188. lc = 0
  189. ptr = lonarr(wc)
  190.  
  191. for i=1, wc-1 do begin    ;Output list, merging words with same anagram
  192.             ;Skip 1st element which is the null string.
  193.     j = i+1
  194.     q = b[c[i]]    ;first word with same anagram
  195.     while q eq b[c[j]] do j=j+1
  196.     out = q        ;Make concatenated string
  197.     for k = i,j-1 do out = out + " " + a[c[k]]
  198.     i = j-1        ;Skip the ones we did.
  199.     printf,lun,out
  200.     q = fstat(lun)
  201.     ptr[lc] = q.cur_ptr    ;Save ^ in file
  202.     lc = lc + 1
  203.     endfor
  204.  
  205. ptr = ptr[0:lc-1]        ;Truncate pointer to proper length
  206. save, file = 'anagrams_ptr.dat', ptr
  207.  
  208. print,"Done, wrote ",lc," lines."
  209. print,systime()
  210. close,lun
  211. openr,lun,'anagrams.dat'    ;Re open to read
  212. point_lun, lun, 0    ;Reset back to beginning    
  213.  
  214. end
  215.  
  216.  
  217.  
  218. pro scrabble, word, double = doub, triple = trip, minchar = minchar
  219. ;+
  220. ; NAME:
  221. ;    SCRABBLE
  222. ;
  223. ; PURPOSE:
  224. ;    Solve Scrabble(R) puzzles.
  225. ;
  226. ; CATEGORY:
  227. ;    Games.
  228. ;
  229. ; CALLING SEQUENCE:
  230. ;    SCRABBLE, Word [, DOUB = Doub, TRIP = Trip, MINCHAR = Minchar]
  231. ;
  232. ; INPUTS:
  233. ;    WORD:    A string representing the letters in the rack.  This string
  234. ;        can be any length, although words of two characters or fewer
  235. ;        are not checked.
  236. ;
  237. ; KEYWORDS:
  238. ;    DOUBLE:    The indices of any double-score letters in WORD where index
  239. ;        0 is the first letter.  Omit this keyword if there are no 
  240. ;        double score letters.  This keyword can be set to a scalar
  241. ;        or an array if there is more than one double score letter.
  242. ;
  243. ;    TRIPLE:    Indices of any triple-score letters in WORD where index
  244. ;        0 is the first letter.  Omit this keyword if ther are no 
  245. ;        triple score letters.  This keyword can be set to a scalar 
  246. ;        or an array if there is more than one triple score letter.
  247. ;
  248. ;      MINCHAR:    The smallest number of characters to consider when matching.
  249. ;        The default is 4.
  250. ;
  251. ; OUTPUTS:
  252. ;    A list of possible words and their scores is output.
  253. ;
  254. ; EXAMPLE:
  255. ;    To work on a rack with the letters "aeimmtw", with the third
  256. ;    letter triple, enter:
  257. ;
  258. ;        SCRABBLE, "aeimmtw", TRIP=2
  259. ;
  260. ; COMMON BLOCKS:
  261. ;    None.
  262. ;
  263. ; SIDE EFFECTS:
  264. ;    Uses the files anagrams.dat and anagrams_ptr.dat.  If these files
  265. ;    don't exist, they are created by the procedure make_anagram.
  266. ;
  267. ; RESTRICTIONS:
  268. ;    Doesn't consider all suffixes.  Uses only the words in 
  269. ;    /usr/dict/words.  The remaining letters are printed after
  270. ;    the word that's found, sometimes making the suffix obvious.
  271. ;    For example, the word "AVIATOR" is not found because the root
  272. ;    word in /usr/dict/words is "AVIATE", and there is no "E" in
  273. ;    "AVIATOR".
  274. ;
  275. ; PROCEDURE:
  276. ;    Uses anagrams.  Misses some words in dictionary that end in common
  277. ;    suffixes such as "ing", "er", "ed", etc.
  278. ;
  279. ; MODIFICATION HISTORY:
  280. ;    DMS, Jan, 1988.
  281. ;-
  282. ;
  283. common scrabble, ptr
  284.  
  285. on_error,2                      ;Return to caller if an error occurs
  286.  
  287. score = [1,3,3,2,1,4,2,4,1,8,5, $ ;a-k
  288.     1,3,1,1,3,10,1,1,1,      $ ;l-t
  289.     1,4,4,10,4,10 ]        ;u - z
  290. nc = strlen(word)        ;Length of rack
  291. word = strlowcase(word)        ;Cvt to lower case
  292.  
  293. weight = replicate(1,nc)    ;Make weights
  294. if n_elements(doub) ne 0 then weight[doub] = 2 ;fill in double weights
  295. if n_elements(trip) ne 0 then weight[trip] = 3
  296.  
  297. ;
  298. get_lun, lun    ;Get a unit number.
  299. on_ioerror, no_anagram
  300. openr,lun,'anagrams.dat'
  301. goto, anagram_ok
  302. ;
  303. no_anagram:        ;Anagram file doesn't exist.  Make it.
  304.     make_anagram, lun
  305. ;
  306. anagram_ok:
  307. if n_elements(ptr) le 0 then restore,file='anagrams_ptr.dat'
  308. ;
  309. ;        Make the anagram of the string:
  310. ;
  311.  
  312. maxscore = 0
  313. if n_elements(minchar) eq 0 then minchar = 4    ;Minimum #  of chars
  314.  
  315. for len = nc, minchar, -1 do begin    ;main loop
  316.     a = part_word(word,len)    ;Get len length combinations
  317.     if n_elements(a) gt 0 then a = remove_dup(a) ;Get rid of duplications
  318.     for i=0,n_elements(a)-1 do begin ;Process each combination
  319.        q = find_word(a[i], lun) ;look up word in anagrams
  320.        while strlen(q) gt 0 do begin    ;Anything there?
  321.         w = head(q)
  322.         s = fix(total(weight * score[byte(w)-97]))
  323.         if strlen(w) ge 7 then s = s + 50
  324.         w = w + " (" + remainder(word,w) + ")"
  325.         print,"Found word: ",w,",  Score ",s
  326.         if s ge maxscore then begin  ;Best score?
  327.             maxscore = s
  328.             result = w
  329.             endif
  330.         endwhile        ;strlen q
  331.     endfor        ;n_elements a
  332. endfor            ;for len
  333.  
  334. if maxscore ne 0 then begin
  335.   if strpos(result," ") ge 7 then $
  336.     print,'50 point bonus for using all 7 letters'
  337.   print,"Final word: ",strupcase(result)," Score ",maxscore
  338.   endif else print,"Found no matches."
  339.     
  340. end
  341.  
  342.  
  343.